import React, { useEffect, useMemo, useRef } from 'react';
import { createPortal } from 'react-dom';
import ScrollLocker from './scrollLocker';

export type GetContainer = string | HTMLElement | (() => HTMLElement);

export interface PortalProps {
  visible: boolean;
  forceRender?: boolean;
  getContainer?: GetContainer;
  children: (params: any) => React.ReactNode;
}

export const getParent = (getContainer?: GetContainer): HTMLElement => {
  if (getContainer) {
    if (typeof getContainer === 'string') {
      return document.querySelectorAll(getContainer)[0] as HTMLElement;
    }
    if (typeof getContainer === 'function') {
      return getContainer();
    }
    if (
      typeof getContainer === 'object' &&
      getContainer instanceof window.HTMLElement
    ) {
      return getContainer;
    }
  }
  return document.body;
};

function Portal(props: PortalProps) {
  const { visible, forceRender = false, getContainer, children } = props;
  const portalDivRef = useRef<HTMLDivElement>(); //临时创建的div
  // const [portalDom, setPortalDom] = useState<React.ReactNode>(null);
  const scrollLockerRef = useRef<ScrollLocker>();

  const getCurContainerAndInsertToParent = () => {
    const containerDom = document.createElement('div');

    const parent = getParent(getContainer);
    parent.appendChild(containerDom);
    portalDivRef.current = containerDom;

    //--scroller
    const scrollLockerInstance = ScrollLocker.getInstance({
      container: parent,
    });
    scrollLockerRef.current = scrollLockerInstance;
    // scrollLockerInstance.lock();

    return containerDom;
  };

  // useLayoutEffect(() => {
  //   if (forceRender || visible) {
  //     if (!portalDivRef.current) { //组件第一次加载时createPortal，且createPortal只能在组件第一次加载时执行 , 但是 children(params) params不会更新了。
  //       setPortalDom(createPortal(children({ visible, forceRender }), getCurContainerAndInsertToParent()));
  //     }
  //   }
  // }, [visible, forceRender, portalDivRef.current])

  const removePortalDiv = () => {
    const parent = getParent(getContainer);
    parent && portalDivRef.current && parent.removeChild(portalDivRef.current);
    scrollLockerRef.current && scrollLockerRef.current.unLock();
  };

  //destroyOnClose:true时 父级组件直接 return null， 执行return 函数
  // destroyOnClose:false时  不会执行return 函数
  useEffect(() => {
    return () => {
      // removeChild， 父级组件直接 return null 时，通过createPortal在别处渲染的子组件会卸载，但是portalDivRef(临时创建的div)会存在，要手动删除
      removePortalDiv();
    };
  }, []);

  //visible变化时每次都执行了createPortal但是children()对应的组件并没有随之加载,卸载(useEffect(() => {},[])只执行了一次 )
  // 第一次加载  portalDivRef.current不存在
  const portalDom = useMemo(() => {
    if (forceRender || visible || portalDivRef.current) {
      // console.log('---Portal---useMemo--visible--:', visible);
      const finalPotalContainer =
        portalDivRef.current || getCurContainerAndInsertToParent();
      return createPortal(
        children({ scrollLocker: scrollLockerRef.current }),
        finalPotalContainer,
      );
    }
    return null;
  }, [
    visible,
    forceRender,
    portalDivRef.current,
    scrollLockerRef.current,
    getContainer,
    children, //一定要监听children的变化，不然这里的children永远是初始化时的children
  ]);

  return portalDom;
}

export default Portal;
